//
//  CameraViewController.swift
//  EasePods
//
//  Created by 易先生 on 2024/4/28.
//

import UIKit
import AVFoundation
import Photos
import RxCocoa

class CameraViewController: ViewController {

    fileprivate var device: AVCaptureDevice?
    
    //输入设备
    fileprivate var input: AVCaptureDeviceInput?
    
    fileprivate var output: AVCaptureMetadataOutput?
        
    fileprivate var photoOutput: AVCapturePhotoOutput?
    
    fileprivate var flashMode: AVCaptureDevice.FlashMode = .auto
    
    private var session: AVCaptureSession = AVCaptureSession()
    
    //图像预览层
    private var previewLayer: AVCaptureVideoPreviewLayer?
    
    private var canCa: Bool!

    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        BluetoothManager.shared.enterCameraView()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigation.item.leftBarButtonItem = UIBarButtonItem.init(customView: leftButton)
        self.navigation.item.rightBarButtonItem = UIBarButtonItem.init(customView: rightButton)
        
    }
    
    override func makeUI() {
        super.makeUI()
        
        self.view.addSubview(cameraView)
        self.view.addSubview(bottomView)
        self.view.addSubview(focusView)

        bottomView.snp.makeConstraints { make in
            make.bottom.equalToSuperview()
            make.leading.trailing.equalToSuperview()
        }
        
        cameraView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(kNavHeight)
            make.leading.trailing.equalToSuperview()
            make.bottom.equalTo(bottomView.snp.top)
        }
        
        focusView.snp.makeConstraints { make in
            make.top.leading.equalToSuperview()
            make.size.equalTo(CGSize(width: 80, height: 80))
        }

        
        canCa = self.canUserCamera()
        if !canPhotoLibrary(){
            PHPhotoLibrary.requestAuthorization { (state) in
                log.debug("state =\(state.rawValue)")
            }
        }
        if canCa {
            self.customCamera()
        }else {
            return
        }
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.previewLayer?.frame = self.cameraView.bounds
    }
    
    override func bindViewModel() {
        super.bindViewModel()
        
        leftButton.rx.tap.subscribe { _ in
            BluetoothManager.shared.exitCameraView()
            RootViewManager.default.rootViewController.dismiss(animated: true)
        }.disposed(by: rx.disposeBag)
        
        BluetoothManager.shared.receiveCameraAction.subscribe(onNext: { [weak self] state in
            if state == 1 {
                self?.takePhoto()
            }
        }).disposed(by: rx.disposeBag)
        
        UIApplication.rx.didEnterBackground.asObservable().subscribe(onNext: { [weak self] _ in
            self?.removeVolumeView()
        }).disposed(by: rx.disposeBag)
    }
    
    private func removeVolumeView(){
        
        let session = AVAudioSession.sharedInstance()
        do {

            //启动音频会话管理,此时会阻断后台音乐的播放.
            try session.setActive(true)

            //设置音频操作类别,表示该应用仅支持音频的播放.
            if #available(iOS 10.0, *) {
                try session.setCategory(.playback, mode: .default, options: [.interruptSpokenAudioAndMixWithOthers])
            } else {
                // Fallback on earlier versions
                session.perform(NSSelectorFromString("setCategory:withOptions:error:"), with: AVAudioSession.Category.playback, with:  [AVAudioSession.CategoryOptions.interruptSpokenAudioAndMixWithOthers])
            }
        }catch{
            log.debug("applicationWillResignActive error =\(error.localizedDescription)")
        }
    }
    
    private func customCamera(){
        self.view.backgroundColor = UIColor.black
        self.device = AVCaptureDevice.default(for: .video)
        if self.device != nil {
            self.input = try? AVCaptureDeviceInput(device: self.device!)
        }else {
            log.debug("device init fail")
            return
        }
        self.output = AVCaptureMetadataOutput()
        self.photoOutput = AVCapturePhotoOutput()
        self.photoOutput?.isHighResolutionCaptureEnabled = true
        self.session = AVCaptureSession()
        self.session.sessionPreset = .photo
        if self.session.canSetSessionPreset(.hd1280x720){
            self.session.sessionPreset = .hd1280x720
        }
        if let input = self.input, self.session.canAddInput(input){
            self.session.addInput(input)
        }
        if let photoOutput = self.photoOutput {
            if self.session.canAddOutput(photoOutput) {
                self.session.addOutput(photoOutput)
            }
        }
        self.previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
        self.previewLayer?.frame = self.cameraView.bounds
        self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
        if let previewLayer = self.previewLayer {
            self.cameraView.layer.insertSublayer(previewLayer, at: 0)
            let tapGesture = UITapGestureRecognizer(target: self, action: #selector(focusGesture(gesture:)))
            self.cameraView.addGestureRecognizer(tapGesture)
        }
        
        DispatchQueue.global(qos: .userInitiated).async {
            self.session.startRunning()
        }
        
        do {
            
            guard let device = self.device  else {
                return
            }
            
            try device.lockForConfiguration()
            if device.isFocusModeSupported(.autoFocus) {
                device.focusMode = .autoFocus
            }
            
            if device.isExposureModeSupported(.autoExpose) {
                device.exposureMode = .continuousAutoExposure
            }
            
            if device.isWhiteBalanceModeSupported(.autoWhiteBalance) {
                device.whiteBalanceMode = .continuousAutoWhiteBalance
            }
            
            
        }catch{
            log.debug("camera run error \(error.localizedDescription)")
        }
        
    }
    
    
    private func canUserCamera()->Bool{
        let authStatus = AVCaptureDevice.authorizationStatus(for: .video)
        if authStatus == AVAuthorizationStatus.denied{
            let alertController = UIAlertController(title: R.string.localizable.home_setting_camera_license_title(), message: R.string.localizable.home_setting_camera_license_message(), preferredStyle: .alert)
            let cancelAction = UIAlertAction(title: R.string.localizable.common_cancel(), style: .cancel, handler: nil)
            let settingAction = UIAlertAction(title: R.string.localizable.common_confirm(), style: .default, handler: { (action) in
                if let url = URL(string: UIApplication.openSettingsURLString) {
                    if UIApplication.shared.canOpenURL(url) {
                        UIApplication.shared.open(url,completionHandler: nil)
                    }
                }
                
            })
            alertController.addAction(cancelAction)
            alertController.addAction(settingAction)
            self.present(alertController, animated: true, completion: nil)
            return false
        }else {
            return true
        }
    }
    
    private func canPhotoLibrary()->Bool{
        let AlbumStatus = PHPhotoLibrary.authorizationStatus()
        log.debug("AlbumStatus =\(AlbumStatus.rawValue)")
        if AlbumStatus == .authorized{
            return true
        }else {
            return false
        }
    }
    
    //触摸对焦
    @objc func focusGesture(gesture: UITapGestureRecognizer){
        let point = gesture.location(in: gesture.view)
        log.debug("point =\(point)")
        let ponitInCamera = CGPoint(x: point.x, y: point.y + self.cameraView.frame.origin.y)
        self.focusAtPoint(point: ponitInCamera)
    }
    
    func focusAtPoint(point: CGPoint){
        let size = self.cameraView.frame.size
        let focusPoint = CGPoint(x: point.y / size.height, y: 1-point.x/size.width)
        log.debug("focusPoint =\(focusPoint)")
        
        do {
            try self.device?.lockForConfiguration()
            if (self.device?.isFocusModeSupported(.autoFocus))!{
                self.device?.focusPointOfInterest = focusPoint
                self.device?.focusMode = .autoFocus
            }
            if (self.device?.isExposureModeSupported(.autoExpose))!{
                self.device?.exposurePointOfInterest = focusPoint
                self.device?.exposureMode = .autoExpose
            }
            
            self.device?.unlockForConfiguration()
            focusView.center = point
            focusView.isHidden = false
            UIView.animate(withDuration: 0.3, animations: {[weak self] in
                self?.focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25)
            }) { (finished) in
                UIView.animate(withDuration: 0.5, animations: {[weak self] in
                    self?.focusView.transform = CGAffineTransform.identity
                    }, completion: { [weak self] (finished) in
                        self?.focusView.isHidden = true
                })
            }
            
        }catch{
            log.debug("camera run error \(error.localizedDescription)")
        }
        
    }
    
    
    @objc private func flash_click(sender: UIButton) {
        
        if self.photoOutput != nil {
            switch flashMode {
            case .off:
                flashMode = .auto
                sender.setImage(R.image.ic_camera_control_lighting_auto(), for: UIControl.State.normal)
            case .on:
                flashMode = .off
                sender.setImage(R.image.ic_camera_control_lighting_off(), for: UIControl.State.normal)
            case .auto:
                flashMode = .on
                sender.setImage(R.image.ic_camera_control_lighting_on(), for: UIControl.State.normal)
            @unknown default:
                sender.setImage(R.image.ic_camera_control_lighting_auto(), for: UIControl.State.normal)
            }
        }
    }
    
    @objc private func showAlbum() {
        
        if canPhotoLibrary() {
            
            let vc = PhotoAlbumViewController()
            self.navigationController?.pushViewController(vc, animated: true)

            
        }else {
            let alertController = UIAlertController(title: R.string.localizable.home_setting_album_license_title(), message: R.string.localizable.home_setting_album_license_message(), preferredStyle: .alert)
            let cancelAction = UIAlertAction(title: R.string.localizable.common_cancel(), style: .cancel, handler: nil)
            let settingAction = UIAlertAction(title: R.string.localizable.common_confirm(), style: .default, handler: { (action) in
                if let url = URL(string: UIApplication.openSettingsURLString) {
                    if UIApplication.shared.canOpenURL(url) {
                        UIApplication.shared.open(url, completionHandler: nil)
                    }
                }
            })
            alertController.addAction(cancelAction)
            alertController.addAction(settingAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }
    
    @objc private func takePhoto() {
        log.debug("Thread.current============\(Thread.current)")
        UIView.animate(withDuration: 0.1) {
            self.bottomView.takePictureButton.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
        } completion: { _ in
            self.bottomView.takePictureButton.transform = CGAffineTransform(scaleX: 1, y: 1)
        }

        // 检查会话是否在运行，如果没有则在后台线程启动会话
        if !self.session.isRunning {
            DispatchQueue.global(qos: .userInitiated).async {
                self.session.startRunning()
            }
        }
        
        DispatchQueue.global(qos: .userInitiated).async {
            if let photoOutput = self.photoOutput {
                let settings = AVCapturePhotoSettings()
                settings.isHighResolutionPhotoEnabled = true
                if photoOutput.supportedFlashModes.contains(self.flashMode) {
                    settings.flashMode = self.flashMode
                }
                photoOutput.capturePhoto(with: settings, delegate: self)
            }
        }
    }
    

    
    @objc private func changeCamera() {
        
        let cameraCount = AVCaptureDevice.DiscoverySession(deviceTypes:[.builtInWideAngleCamera], mediaType: .video, position: .unspecified).devices.count
        
        if cameraCount > 1 {
            let animation = CATransition()
            animation.duration = 0.5
            animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
            animation.type = CATransitionType(rawValue: "oglFlip")
            var newCamera: AVCaptureDevice? = nil
            var newInput: AVCaptureDeviceInput? = nil
            let position = self.input?.device.position
            if position == AVCaptureDevice.Position.front{
                newCamera = self.cameraWithPosition(position: AVCaptureDevice.Position.back)
                animation.subtype = .fromLeft
            }else {
                newCamera = self.cameraWithPosition(position: AVCaptureDevice.Position.front)
                animation.subtype = .fromRight
            }
            
            do {
                newInput = try? AVCaptureDeviceInput(device: newCamera!)
                self.previewLayer?.add(animation, forKey: nil)
                if newInput != nil {
                    self.session.beginConfiguration()
                    self.session.removeInput(input!)
                    if self.session.canAddInput(newInput!){
                        self.session.addInput(newInput!)
                        self.input = newInput
                    }else {
                        self.session.addInput(self.input!)
                    }
                    self.session.commitConfiguration()
                }
            }
        }
    }
    
    private func cameraWithPosition(position: AVCaptureDevice.Position)->AVCaptureDevice?{
        
        let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: .unspecified).devices
        for device in devices{
            if device.position == position{
                return device
            }
        }
        return nil
    }

    private lazy var leftButton: Button = {
        let button = Button(type: .custom)
        button.frame = CGRect(x: 0, y: 0, width: 39, height: 44)
        button.setImage(R.image.ic_common_nav_back(), for: .normal)
        button.contentHorizontalAlignment = .leading
        return button
    }()
    
    private lazy var rightButton: Button = {
        let button = Button(type: .custom)
        button.setImage(R.image.ic_camera_control_lighting_auto(), for: .normal)
        button.addTarget(self, action: #selector(flash_click(sender:)), for: .touchUpInside)
        return button
    }()
    
    private lazy var cameraView: View = {
        let view = View()
        return view
    }()
    
    private lazy var bottomView: CameraBottomView = {
        let view = CameraBottomView()
        view.backgroundColor = R.color.common_2_bg_page()
        view.albumButton.addTarget(self, action: #selector(showAlbum), for: .touchUpInside)
        view.takePictureButton.addTarget(self, action: #selector(takePhoto), for: .touchUpInside)
        view.transButton.addTarget(self, action: #selector(changeCamera), for: .touchUpInside)
        return view
    }()
    
    private lazy var focusView: View = {
        let focusView = View()
        focusView.layer.borderWidth = 1.0
        focusView.layer.borderColor = UIColor.green.cgColor
        focusView.backgroundColor = UIColor.clear
        focusView.isHidden = true
        return focusView
    }()
}

extension CameraViewController: AVCapturePhotoCaptureDelegate {
    
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        
        guard error == nil else {
            self.view.makeToast("error:\(error?.localizedDescription ?? "camera error")", duration: 2)
            return
        }
        
        guard let imageData = photo.fileDataRepresentation(),
              let image = UIImage(data: imageData) else {
            self.view.makeToast("error: 没有图片", duration: 2)
            return
        }
        
        self.saveImageToPhotoAlbum(image: image)
        DispatchQueue.main.async {
            self.bottomView.albumButton.setBackgroundImage(image, for: UIControl.State.normal)
        }
    }
    
    func saveImageToPhotoAlbum(image: UIImage){
        
        UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.savedImage(image:didFinishSavingWithError:contextInfo:)), nil)
    }
    
    @objc func savedImage(image:UIImage,didFinishSavingWithError error:NSError?,contextInfo:AnyObject) {
        
        DispatchQueue.global(qos: .userInitiated).async {
            self.session.startRunning()
        }
    }
    
}

class CameraBottomView: View {
    
    override func makeUI() {
        super.makeUI()
        
        self.addSubview(albumButton)
        self.addSubview(takePictureView)
        takePictureView.addSubview(takePictureButton)
        self.addSubview(transButton)
        
        takePictureView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(10)
            make.centerX.equalToSuperview()
            make.size.equalTo(CGSize(width: 76, height: 76))
            make.bottom.equalToSuperview().offset(-44)
        }
        
        takePictureButton.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(CGSize(width: 66, height: 66))
        }
        
        albumButton.snp.makeConstraints { make in
            make.trailing.equalTo(takePictureView.snp.leading).offset(-54)
            make.centerY.equalTo(takePictureView)
            make.size.equalTo(CGSize(width: 54, height: 54))
        }
        
        transButton.snp.makeConstraints { make in
            make.leading.equalTo(takePictureView.snp.trailing).offset(70)
            make.centerY.equalTo(takePictureView)
        }
    }
    
    public lazy var albumButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = R.color.equalizer_5_disconnect()
        button.layer.cornerRadius = 4
        return button
    }()
    
    private lazy var takePictureView: View = {
        let view = View()
        view.layer.borderColor = R.color.common_27_main_color()?.cgColor
        view.layer.borderWidth = 2
        view.layer.cornerRadius = 38
        return view
    }()
    
    public lazy var takePictureButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = R.color.common_27_main_color()
        button.layer.cornerRadius = 33
        return button
    }()
    
    public lazy var transButton: UIButton = {
        let button = UIButton()
        button.setImage(R.image.ic_camera_control_turnover(), for: .normal)
        return button
    }()
}
